package com.atguigu.exam.service.impl;

import com.atguigu.exam.entity.Question;
import com.atguigu.exam.entity.QuestionAnswer;
import com.atguigu.exam.entity.QuestionChoice;
import com.atguigu.exam.exception.ExamException;
import com.atguigu.exam.mapper.QuestionAnswerMapper;
import com.atguigu.exam.mapper.QuestionChoiceMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.QuestionService;
import com.atguigu.exam.vo.AiGenerateRequestVo;
import com.atguigu.exam.vo.QuestionImportVo;
import com.atguigu.exam.vo.QuestionQueryDto;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 题目Service实现类
 * 实现题目相关的业务逻辑
 */
@Slf4j
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {


    @Autowired
    private QuestionAnswerMapper questionAnswerMapper;

    @Autowired
    private QuestionChoiceMapper questionChoiceMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Page<Question> getPageByCondition(Page<Question> questionPage, QuestionQueryDto queryDto) {
        //调用QuestionMapper的分页及带条件查询的方法
        Page<Question> questionPage1 = baseMapper.getPageByCondition(questionPage, queryDto);
        return questionPage1;
    }


    @Override
    public Page<Question> getPageByConditionWithStream(Page<Question> questionPage, QuestionQueryDto queryDto) {
        //创建LambdaQueryWrapper对象，用于构建查询条件
        LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //封装查询条件
        questionLambdaQueryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getCategoryId()), Question::getCategoryId, queryDto.getCategoryId());
        questionLambdaQueryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getDifficulty()), Question::getDifficulty, queryDto.getDifficulty());
        questionLambdaQueryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getType()), Question::getType, queryDto.getType());
        questionLambdaQueryWrapper.like(ObjectUtils.isNotEmpty(queryDto.getKeyword()), Question::getTitle, queryDto.getKeyword());
        //调用自带的分页及带条件查询的方法查询题目列表
        questionPage = baseMapper.selectPage(questionPage, questionLambdaQueryWrapper);
        //获取当前页中的集合
        List<Question> pageQuestionList = questionPage.getRecords();
        //验空
        if (!CollectionUtils.isEmpty(pageQuestionList)) {
            //给题目设置答案和选项
            fillAnswerAndChoices(pageQuestionList);
        }
        return questionPage;
    }

    @Override
    public int batchImportQuetions(List<QuestionImportVo> questions) {
        //验空
        if (CollectionUtils.isEmpty(questions)) {
            throw new ExamException(12311, "导入的题目数据不能为空");
        }
        //设计一个变量统计成功导入的题目数量
        int successCount = 0;
        //遍历题目列表
        for (QuestionImportVo questionImportVo : questions) {
            //创建Question对象
            Question question = new Question();
            //使用BeanUtils.copyProperties方法将QuestionImportVo对象中的属性复制到Question对象中
            BeanUtils.copyProperties(questionImportVo, question);
            //判断是否是选择题
            if ("CHOICE".equals(questionImportVo.getType())) {
                //获取选项
                List<QuestionImportVo.ChoiceImportDto> choices = questionImportVo.getChoices();
                //创建一个List<ChoiciesImportDto>对象,用于存储选项
                List<QuestionChoice> questionChoicesList = new ArrayList<>();
                //遍历选项列表
                for (QuestionImportVo.ChoiceImportDto choiceImportDto : choices) {
                    //创建QuestionChoice对象
                    QuestionChoice questionChoice = new QuestionChoice();
                    //使用BeanUtils.copyProperties方法将QuestionImportVo.ChoiceImportDto对象中的属性复制到QuestionChoice对象中
                    BeanUtils.copyProperties(choiceImportDto, questionChoice);
                    //添加到列表
                    questionChoicesList.add(questionChoice);
                }
                //将选项列表设置到Question对象中
                question.setChoices(questionChoicesList);
            }
            //创建QuestionAnswer对象
            QuestionAnswer questionAnswer = new QuestionAnswer();
            //判断是否是判断题
            if ("JUDGE".equals(questionImportVo.getType())) {
                //将小写的true转换成大写的TRUE
                String upperCaseAnswer = questionImportVo.getAnswer().toUpperCase();
                //设置答案
                questionAnswer.setAnswer(upperCaseAnswer);
            } else {//若是简答题
                questionAnswer.setAnswer(questionImportVo.getAnswer());
            }
            //将QuestionAnswer对象设置到Question对象中
            question.setAnswer(questionAnswer);
            try {
                //将题目插入到数据库中
                createQuestion(question);
                successCount++;
            } catch (Exception e) {
                throw new ExamException(1000,"第"+successCount+1+"题<"+question.getTitle()+">插入失败，失败原因："+e.getMessage());
            }
        }
        return successCount;
    }

//    @Override
//    public Page<Question> getPageByConditionWithEasy(Page<Question> questionPage, QuestionQueryDto queryDto) {
//        //创建LambdaQueryWrapper对象，用于构建查询条件
//        LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        //封装查询条件
//        questionLambdaQueryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getCategoryId()),Question::getCategoryId,queryDto.getCategoryId());
//        questionLambdaQueryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getDifficulty()),Question::getDifficulty,queryDto.getDifficulty());
//        questionLambdaQueryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getType()),Question::getType,queryDto.getType());
//        //调用自带的分页及带条件查询的方法查询题目列表
//        questionPage = baseMapper.selectPage(questionPage, questionLambdaQueryWrapper);
//        //获取当前页中的集合
//        List<Question> pageQuestionList = questionPage.getRecords();
//        //遍历当前页中的题目列表
//        pageQuestionList.forEach(question -> {
//            //获取当前题目的ID
//            Long questionId = question.getId();
//            //根据题目ID查询题目答案
//            QuestionAnswer questionAnswer = questionAnswerMapper.selectOne(new LambdaQueryWrapper<QuestionAnswer>().eq(QuestionAnswer::getQuestionId,questionId));
//            //设置答案
//            question.setAnswer(questionAnswer);
//            //判断当前题是不是选择题或判断题
//            if("CHOICE".equals(question.getType()) || "JUDGE".equals(question.getType())){
//                //根据题目id获取所有的选项
//                //创建LambdaQueryWrapper对象，用于构建查询条件
//                LambdaQueryWrapper<QuestionChoice> questionChoiceLambdaQueryWrapper = new LambdaQueryWrapper<>();
//                //封装查询条件
//                questionChoiceLambdaQueryWrapper.eq(QuestionChoice::getQuestionId,question.getId());
//                //调用QuestionChoiceMapper的带条件查询的方法
//                List<QuestionChoice> questionChoices = questionChoiceMapper.selectList(questionChoiceLambdaQueryWrapper);
//                //排序
//                questionChoices.sort((o1, o2) -> o1.getSort().compareTo(o2.getSort()));
//                //将选项设置到题目中
//                question.setChoices(questionChoices);
//            }
//        });
//        return questionPage;
//    }

    @Override
    public Question getQuestionDetailsById(Long id) {
        Question question = baseMapper.getQuestionDetailsById(id);
        //创建线程,异步获取题目详情
        new Thread(() -> {
            redisTemplate.opsForZSet().incrementScore("question:popular",id,1);

        }).start();
        return question ;
    }

    //给题目设置答案和选项的方法
    private void fillAnswerAndChoices(List<Question> pageQuestionList) {
        //获取所有题目的ID
        List<Long> questionIds = pageQuestionList.stream().map(Question::getId).collect(Collectors.toList());
        //根据题目ID查询所有的答案
        LambdaQueryWrapper<QuestionAnswer> questionAnswerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //封装查询条件
        questionAnswerLambdaQueryWrapper.in(QuestionAnswer::getQuestionId, questionIds);
        //调用QuestionAnswerMapper的带条件查询的方法
        List<QuestionAnswer> questionAnswers = questionAnswerMapper.selectList(questionAnswerLambdaQueryWrapper);
        //将答案以题目ID为key，答案列表为value，转换为Map
        Map<Long, QuestionAnswer> questionAnswerMap = questionAnswers.stream().collect(Collectors.toMap(QuestionAnswer::getQuestionId, q -> q));
        //遍历所有的题目
        pageQuestionList.forEach(question -> {
            //根据题目ID获取当前题目的答案
            QuestionAnswer questionAnswer = questionAnswerMap.get(question.getId());
            //给题目设置答案
            question.setAnswer(questionAnswer);
            //判断当前题是不是选择题或判断题
            if ("CHOICE".equals(question.getType()) || "JUDGE".equals(question.getType())) {
                //根据题目id获取所有的选项
                //创建LambdaQueryWrapper对象，用于构建查询条件
                LambdaQueryWrapper<QuestionChoice> questionChoiceLambdaQueryWrapper = new LambdaQueryWrapper<>();
                //封装查询条件
                questionChoiceLambdaQueryWrapper.eq(QuestionChoice::getQuestionId, question.getId());
                //调用QuestionChoiceMapper的带条件查询的方法
                List<QuestionChoice> questionChoices = questionChoiceMapper.selectList(questionChoiceLambdaQueryWrapper);
                //排序
                questionChoices.sort((o1, o2) -> o1.getSort().compareTo(o2.getSort()));
                //将选项设置到题目中
                question.setChoices(questionChoices);
            }
        });
    }

    @Transactional
    @Override
    public void createQuestion(Question question) {
        //判断在当前类型种是否已经存在该题目
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Question>().eq(Question::getType, question.getType()).eq(Question::getTitle, question.getTitle()));
        if (exists) {
            //抛出异常
            throw new ExamException(444, "在<" + question.getType() + ">类型中已经存在该题目");
        }
        //1.调用MyBatis Plus自带的方法保存题目
        baseMapper.insert(question);
        //获取题目的答案
        QuestionAnswer answer = question.getAnswer();
        //获取数据库自增的题目的ID
        Long questionId = question.getId();
        //设置题目ID
        answer.setQuestionId(questionId);
        //判断是否是选择题
        if ("CHOICE".equals(question.getType())) {
            //获取所有的选项
            List<QuestionChoice> choices = question.getChoices();
            //创建一个StringBuilder对象，用于拼接选项内容
            StringBuilder choiceContent = new StringBuilder();
            //遍历
            for (int i = 0; i < choices.size(); i++) {
                //获取每一个选项
                QuestionChoice choice = choices.get(i);
                //设置题目ID
                choice.setQuestionId(questionId);
                //设置选项的排序
                choice.setSort(i);
                //2.如果是选择题保存选项
                questionChoiceMapper.insert(choice);
                //判断当前选项是否是正确答案
                if (choice.getIsCorrect()) {
                    if (choiceContent.length() > 0) {
                        choiceContent.append(",");
                    }
                    choiceContent.append((char) ('A' + i));
                }
            }
        }
    }

    @Transactional
    @Override
    public void updateQuestion(Question question) {
        //创建LambdaQueryWrapper对象，用于构建查询条件
        LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //封装查询条件
        //限定相同题目类型，确保只在同一类型内检查重复
        //检查是否有相同标题的题目，避免题目内容重复
        //排除当前正在更新的题目本身，因为题目本身不应该被认为是重复的
        questionLambdaQueryWrapper.eq(Question::getType , question.getType())
                .eq(Question::getTitle, question.getTitle())
                .ne(Question::getId, question.getId());
        //调用MyBatis Plus自带的方法查询
        boolean exists = baseMapper.exists(questionLambdaQueryWrapper);
        if (exists) {
            //抛出异常
            throw new ExamException(444, "在<" + question.getType() + ">类型中已经存在该题目");
        }
        //调用MyBatis Plus自带的方法更新题目
        baseMapper.updateById(question);
        //获取题目的答案
        QuestionAnswer answer = question.getAnswer();
        //判断是不是选择题
        if ("CHOICE".equals(question.getType())) {
            //删除旧的选项
            questionChoiceMapper.delete(new LambdaQueryWrapper<QuestionChoice>().eq(QuestionChoice::getQuestionId, question.getId()));
            //获取新的选项
            List<QuestionChoice> choices = question.getChoices();
            //创建一个StringBuilder对象，用于拼接选项内容
            StringBuilder choiceContent = new StringBuilder();
            //遍历
            for (int i = 0; i < choices.size(); i++) {
                //获取每一个选项
                QuestionChoice choice = choices.get(i);
                //设置ID为null
                choice.setId(null);
                //设置创建时间和更新时间为null
                choice.setCreateTime(null);
                choice.setUpdateTime(null);
                //设置选项的排序
                choice.setSort(i);
                //2.如果是选择题保存选项
                questionChoiceMapper.insert(choice);
                //判断当前选项是否是正确答案
                if (choice.getIsCorrect()) {
                    if (choiceContent.length() > 0) {
                        choiceContent.append(",");
                    }
                    choiceContent.append((char) ('A' + i));
                }
            }

            //将正确答案设置到answer中
            answer.setAnswer(choiceContent.toString());
        }
        //更新题目答案
        questionAnswerMapper.updateById(answer);
        }

    @Override
    public List<QuestionImportVo>  generateQuestionsByAi(AiGenerateRequestVo request) {





        return List.of();
    }

    @Override
    public List<Question> getPopularQuestions(Integer size) {
        //从redis中获取热门题目的id
        Set<Object> redisquestionIds = redisTemplate.opsForZSet().reverseRange("question:popular", 0, size - 1);
        //根据题目id将题目从数据库里查出来
        List<Question> redisquestions = baseMapper.selectList(new LambdaQueryWrapper<Question>().in(Question::getId, redisquestionIds));
        //将查询到的题目反转
        Collections.reverse(redisquestions);
        //获取redis中热门题目的数量
        int redisSize = redisquestionIds.size();
        //计算差值
        int diff = size - redisSize;
        if (diff > 0) {
            //说明redis中题目的数量不足size，需要从数据库中获取
            LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            //封装查询条件
            questionLambdaQueryWrapper.orderByDesc(Question::getCreateTime);
            //查询的题目需要是redis中没有的
            questionLambdaQueryWrapper.notIn(Question::getId, redisquestionIds);
            //在sql语句最后加上 limit
            questionLambdaQueryWrapper.last("limit " + diff);
            //执行
            List<Question> dbquestions = baseMapper.selectList(questionLambdaQueryWrapper);
            //将查询到的题目添加到redisquestion中
            redisquestions.addAll(dbquestions);
        }

        return redisquestions;
    }

}

